package com.qili.controller;

import cn.hutool.core.util.IdUtil;
import com.qili.annotation.TokenCheck;
import com.qili.base.entity.CurrentMenu;
import com.qili.base.entity.CurrentRole;
import com.qili.base.entity.CurrentUser;
import com.qili.core.filter.VerifyCodeUtils;
import com.qili.core.shiro.Principal;
import com.qili.entity.base.BaseCompany;
import com.qili.entity.supervisor.SupervisorFile;
import com.qili.entity.sys.SysRole;
import com.qili.entity.sys.SysUser;
import com.qili.redis.RedisService;
import com.qili.service.SysUserService;
import com.qili.service.base.BaseCompanyService;
import com.qili.service.supervisor.SupervisorFileService;
import com.qili.util.*;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.spring.web.json.Json;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * @author zengyuli
 * @date 2021/9/24
 * @description App登录业务
 */
@Controller
@Slf4j
@RequestMapping("/app")
public class AppLoginController {
    @Autowired
    SysUserService userService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private SupervisorFileService supervisorFileService;

    @Autowired
    private BaseCompanyService  baseCompanyService;


    /**
     * @author zengyuli
     * @date 2021/9/24
     * @description 获取验证码
     */
    @ApiOperation(value = "/getCode", httpMethod = "GET", notes = "验证码{}")
    @GetMapping(value = "/getCode")
    @ResponseBody
    public JsonUtil appGetCode(HttpServletResponse response, HttpSession session) {
        try {
            HashMap map = new HashMap();
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setContentType("image/jpg;");
            //生成随机字串
            String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
            String id = IdUtil.simpleUUID();
            //存入会话session
            redisService.set(id + "code", verifyCode.toLowerCase(), 172800l);
            //生成图片
            int w = 146, h = 33;
            String imageRe = VerifyCodeUtils.outputImageApp(w, h, response.getOutputStream(), verifyCode);
            map.put("code", "data:image/jpg;base64," + imageRe);
            map.put("id", id);
            return JsonUtil.sucessWithData("登录成功", map);
        } catch (Exception e) {
            e.printStackTrace();
            return JsonUtil.error("获取失败");
        }

    }

    /**
     * @author zengyuli
     * @date 2021/9/24
     * @description 登录
     */
    @ApiOperation(value = "/login", httpMethod = "POST", notes = "登录method")
    @PostMapping(value = "/login")
    @ResponseBody
    public JsonUtil appLogin(@RequestBody SysUser user, String rememberMe, HttpSession session) {
//        String codeId = user.getCodeId();
        //  20211217 app 应李士宽要求 去掉验证码
//        Object codeObj = redisService.get(codeId + "code");
//        if (codeObj == null) {
//            throw new RuntimeException("没有获取到验证码");
//        }
//        String code = user.getCode();
//        if (StringUtil.isBlank(code) || !code.equals(codeObj.toString())) {
//            return JsonUtil.error("验证码有误");
//        }
        CustomUsernamePasswordToken token = new CustomUsernamePasswordToken(user.getUsername(), user.getPassword(), "UserLogin", rememberMe);
        Subject subject = Principal.getSubject();
        try {
            subject.login(token);
            if (subject.isAuthenticated()) {
                Example example = new Example(SysUser.class);
                example.and().andEqualTo("username", user.getUsername());
                SysUser thisUser = userService.selectOneByExample(example);
                // 正中人员
                if("001".equals(thisUser.getSource())  && StringUtils.isNotBlank(thisUser.getCompanyName()) ){
                    BaseCompany baseCompany = baseCompanyService.selectByPrimaryKey(thisUser.getCompanyName());
                    if(baseCompany!=null){
                        thisUser.setCompanyName( baseCompany.getBcName());
                    }
                }
                SysUser updateUser = new SysUser();
                updateUser.setLastLoginTime(DateUtil.getCurrentDateTimeString());
                userService.updateByExampleSelective(updateUser, example);
                // 获取所有的权限
                ArrayList<String> qxlist = new ArrayList<>();
                CurrentUser cUser = (CurrentUser) Principal.getSession().getAttribute("currentPrincipal");
                for (CurrentMenu cMenu : cUser.getCurrentMenuList()) {
                    if (!StringUtils.isEmpty(cMenu.getPermission())) {
                        qxlist.add(cMenu.getPermission());
                    }
                }
                // 存入权限
                thisUser.setQxlist(qxlist);
                List<CurrentRole> currentRoleList = cUser.getCurrentRoleList();
                List<String> roleNames=new ArrayList<>();
                for (int i = 0; i <currentRoleList.size() ; i++) {
                    roleNames.add(currentRoleList.get(i).getRoleName());
                }
                String sign = JWTUtil.sign(thisUser.getUsername(), thisUser.getId(), roleNames, thisUser.getPassword());
                thisUser.setToken(sign);
                redisService.set("token_"+sign,sign,172800l);
                // 生成token
                // 监理上传
                return JsonUtil.sucessWithData("登录成功", thisUser);
            }
        } catch (UnknownAccountException | IncorrectCredentialsException e) {
            return JsonUtil.error("用户名/密码错误");
        } catch (ExcessiveAttemptsException e) {
            return JsonUtil.error("登录失败多次，账户锁定10分钟");
        }
        return JsonUtil.error("登录失败");
    }


    /**
     * 根据用户名修改密码
     *
     * @param sysUser
     * @return
     */
    @ApiOperation(value = "/updatePassword", httpMethod = "POST", notes = "修改密码")
    @PostMapping(value = "/updatePassword")
    @ResponseBody
    @TokenCheck
    public JsonUtil updatePasswordByUsername(@RequestBody SysUser sysUser) {
        //获取用户名
        String username = sysUser.getUsername();
        //获取新密码
        String password = sysUser.getPassword();
        //获取旧密码
        String oldPassword = sysUser.getOldPassword();
        //根据用户名查询用户
        SysUser selectUser = userService.selectUser(username);
        if (selectUser == null) {
            return JsonUtil.error("未查询到用户");
        }
        //取出数据库中的旧密码 与前端传的旧密码比对
        String realOldPassword = selectUser.getPassword();
        //处理前端传的旧密码 进行MD5转换
        oldPassword = Md5Util.getMD5(oldPassword.trim(), username.trim());
        if (!realOldPassword.equals(oldPassword)) {
            return JsonUtil.error("原密码错误，修改失败");
        }
        // 全部验证通过 修改用户密码为新密码
        //处理新密码
        password = Md5Util.getMD5(password.trim(), username.trim());
        //根据用户名修改密码
        int count = userService.updatePasswordUsername(username, password);
        if (count <= 0) {
            return JsonUtil.error("修改密码失败");
        }
        return JsonUtil.sucess("修改密码成功");
    }

    /**
     * APP 修改密码 - 校验密码格式
     * @param password
     * @return
     */
    @ApiOperation(value = "/checkPass", httpMethod = "POST", notes = "校验密码格式")
    @PostMapping(value = "/checkPass")
    @ResponseBody
    public JsonUtil checkPassword(@RequestBody String password){

        if(StringUtils.isNotBlank(password)){
            // 验证密码===>不少于8个字符,并且是大写字母 小写字母  数字  特殊字符的至少三种
            if (this.checkUserPassword(password)){
                return JsonUtil.sucess("密码格式符合相关规则");
            }
        }
        return JsonUtil.error("修改密码失败，密码格式错误！");
    }

    /**
     * 验证密码 不少于8个字符,并且是大写字母 小写字母  数字  特殊字符的至少三种
     * @param password
     * @return
     */
    private boolean checkUserPassword(String password){
        //特殊符号
//        String REG_SYMBOL = ".*[~!@#$%^&*()_+|<>,.?/:;'\\[\\]{}\"]+.*";
        String REG_SYMBOL = ".*[~!@#$%^&*]+.*";
        if(password.length() < 8){
            return false;
        }
        int alphaLower = 0;
        int alphaUpper = 0;
        int number = 0;
        int is_ = 0;
        for(int i=0;i<password.length();i++){
            char c = password.charAt(i);
            //如果是小写字母:
            if(CharUtils.isAsciiAlphaLower(c)){
                alphaLower = 1;
            }else if(CharUtils.isAsciiAlphaUpper(c)){
                alphaUpper = 1;
            }else if(CharUtils.isAsciiAlphanumeric(c)){
                number = 1;
            }else if (String.valueOf(password).matches(REG_SYMBOL)){
                is_ = 1;
            }else{
                return false;
            }
        }
        if((alphaLower + alphaUpper + number + is_) < 3){
            return false;
        }
        return true;
    }


    /**
     * @author zengyuli
     * @date 2021/9/26
     * @description 获取手机验证码
     */
    @ApiOperation(value = "/getPhoneCode", httpMethod = "POST", notes = "手机验证码{}")
    @PostMapping(value = "/getPhoneCode")
    @ResponseBody
    public JsonUtil appGetPhoneCode(String phone, HttpSession session) {
        try {
            //根据手机号查询用户是否存在
            SysUser sysUser = userService.phoneLogin(phone);
            if (sysUser == null) {
                return JsonUtil.error("手机号不存在");
            }
            //生成随机数
            String randomString = RandomStringUtils.randomNumeric(6);
            //将验证码存到redis中 以手机号为Key 随机字符串为value
            redisService.set(phone + "code", randomString, 300L);
            //齐力短信平台 给手机号发送短信 TODO
            //获取yml文件参数
            YamlPropertiesFactoryBean yamlMapFactoryBean = new YamlPropertiesFactoryBean();
            //可以加载多个yml文件
            yamlMapFactoryBean.setResources(new ClassPathResource("application-mysql-dev.yml"));
            Properties properties = yamlMapFactoryBean.getObject();
            //获取yml里的参数
            String userid = properties.getProperty("smsCustom.userid");
            String account = properties.getProperty("smsCustom.account");
            String password = properties.getProperty("smsCustom.password");
            String content = properties.getProperty("smsCustom.content");
            String checkcontent = properties.getProperty("smsCustom.checkcontent");
            content = content.replace("randomString", randomString);
            // 调用短信发送接口
            CloseableHttpClient clients = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost("http://pt.sdqlweb.com/sms.aspx?action=send&userid=" + userid + "&account=" + account + "&password=" + password + "&mobile=" + phone + "&content=" + content + "&sendTime=&checkcontent=" + checkcontent);
            CloseableHttpResponse response = clients.execute(httpPost);
            //获取结果实体
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                //按指定编码转换结果实体为String类型
                String body = EntityUtils.toString(entity, "UTF-8");
                Document doc = DocumentHelper.parseText(body);
                Element root = doc.getRootElement();
                if (!"ok".equals(root.elementText("message"))) {
                    return JsonUtil.error("发送失败！");
                }
            }
            return JsonUtil.sucess("发送成功！");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return JsonUtil.error("发送失败！");
    }

    /**
     * zyl
     * 根据手机号验证码修改密码
     *
     * @param user
     * @return
     */
    @PostMapping("updatePasswordByPhone")
    @ResponseBody
    @TokenCheck
    public JsonUtil appUpdatePasswordByPhone(SysUser user) {
        //取手机号
        String phoneNumber = user.getPhoneNumber();
        //取前端验证码
        String code = user.getCode();
        //取前端新密码
        String password = user.getPassword();
        //获取redis中此手机号的正确验证码
        String redisCode = redisService.get(phoneNumber + "code");
        if (StringUtil.isBlank(redisCode)) {
            return JsonUtil.error("未查询到验证码");
        }
        //进行对比
        if (!redisCode.equals(code)) {
            return JsonUtil.error("验证码有误");
        }
        //对比通过 查询用户
        SysUser sysUser = userService.phoneLogin(phoneNumber);
        if (sysUser == null) {
            return JsonUtil.error("未查询到用户");
        }
        //密码加密
        password = Md5Util.getMD5(password.trim(), sysUser.getUsername().trim());
        //根据用户手机号修改用户密码字段
        int count = userService.updateUserPassWordByPhone(phoneNumber, password);
        if (count == 0) {
            return JsonUtil.error("修改密码失败");
        }
        return JsonUtil.sucess("修改密码成功");
    }

    /**
    * @Author:zhaoyongke
    * @Description: 获取 头像
    * @Date:10:05 2021/11/15
    */
    @PostMapping(value = "/getUserImage")
    @ResponseBody
    @TokenCheck
    public JsonUtil getUserImage(@RequestBody SysUser sysUser) {
        try {
            String userId = sysUser.getId();
            if(StringUtils.isBlank(userId)){
                return JsonUtil.error("参数获取失败");
            }
            SupervisorFile supervisorFile = supervisorFileService.getPersonalImg(userId);
            HashMap  map=new HashMap();
            map.put("file",supervisorFile);
            return JsonUtil.sucessWithData("成功",map);
        } catch (Exception e) {
            e.printStackTrace();
            return JsonUtil.error("获取失败");
        }


    }

    public static void main(String[] args) {
        String admin = Md5Util.getMD5("12345678", "admin");
        System.out.println(admin);
    }
}
